/*
 * Copyright (C) 2010 Young, Fey <fey.young@gmail.com>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package com.youngfey.ebs

import com.youngfey.util.math.Random

/**
 * A Monte Carlo simulator
 * @author Young, Fey <fey.young@gmail.com>
 */
class Estimator {
    /**
     * How many scenarios it estimate, should be as big as posible (as long as it
     * won't spend to much time)
     */
    int repeats = 3000

    /**
     * History.weight could be a float or a double value, which will be divided
     * to many equal parts, each parts is a step, so if weightSteps = 100, then
     * the first step is (0, 0.01], and the second is (0.01, 0.02]...
     */
    int weightSteps = 20

    /**
     * Convert histories to a random velocity list
     */
    void setHistories(histories) {
        velocities = []
        histories.each { h->
            (h.weight * weightSteps).times { velocities << h.velocity }
        }
    }

    /**
     * Use the Monte Carlo Simulation to create several possible scenarios
     * @param steps Estimates you made
     * @return (lots of) estimates computer made
     */
    List<List<Number>> estimate(List<Number> steps) {
        validate()
        def results = []
        repeats.times {
            results << steps.collect { s->
                s * Random.pick(velocities)
            }
        }
        results
    }

    private validate() {
        if(repeats <= 0 || weightSteps < 1 || !velocities)
            throw new IllegalStateException("Status: ${toString()}")
    }

    private velocities
}
